let constants = require('./constants');
let utils = require('./utils');
let Session = require('./session');
let loginLib = require('./login');

let noop = function noop() {
};

let buildSessionHeader = function buildSessionHeader() {
    let session = Session.get();
    let header = {
        "Content-Type": "application/json",
        "organId": "1000000",
        "clientId": "ALT",
        "clientSecret": "48CD11D8EF0F45935AA2BE33C52764EA",
        "scope": "01",
        "version": "ALT:V1.0.0",
        "Authorization": ""
    };
    if (session && session.token) {
        header[constants.WX_HEADER_TOKEN] = session.token;
    }
    if (session && session.loginInfo.accessToken) {
        header["Authorization"] = session.loginInfo.accessToken;
    }
    return header;
};

/***
 * @class
 * 表示请求过程中发生的异常
 */
let RequestError = (function () {
    function RequestError(type, message) {
        Error.call(this, message);
        this.type = type;
        this.message = message;
    }

    RequestError.prototype = new Error();
    RequestError.prototype.constructor = RequestError;
    return RequestError;
})();

function request(options) {
    if (typeof options !== 'object') {
        let message = '请求传参应为 object 类型，但实际传了 ' + (typeof options) + ' 类型';
        throw new RequestError(constants.ERR_INVALID_PARAMS, message);
    }

    let requireLogin = options.login;
    let success = options.success || noop;
    let fail = options.fail || noop;
    let complete = options.complete || noop;
    let originHeader = options.header || {};

    // 成功回调
    let callSuccess = function () {
        success.apply(null, arguments);
        complete.apply(null, arguments);
    };

    // 失败回调
    let callFail = function (error) {
        fail.call(null, error);
        complete.call(null, error);
    };

    // 是否已经进行过重试
    let hasRetried = false;
    if (requireLogin) {
        doRequestWithLogin();
    } else {
        doRequest();
    }

    // 登录后再请求
    function doRequestWithLogin() {
        loginLib.login({
            success: doRequest,
            fail: callFail
        });
    }

    // 实际进行请求的方法
    function doRequest() {
        let authHeader = buildSessionHeader();
        wx.request(utils.extend({}, options, {
            header: utils.extend({}, originHeader, authHeader),
            success: function (response) {
                let data = response.data;
                let error, message;
                if (data) {
                    if (!data.errorCode || data.errorCode == 0) {
                        callSuccess.apply(null, arguments);
                        return;
                    } else if (data.code == constants.CODE_USER_TOKEN_FAIL) {
                        // 清除登录态
                        Session.clear();
                        if (!hasRetried) {
                            hasRetried = true;
                            doRequestWithLogin();
                            return;
                        }

                        message = data.msg;
                        error = new RequestError(data.code, message);
                    } else {
                        message = data.msg;
                        error = new RequestError(data.code, message);
                    }
                } else {
                    message = '未知错误';
                    error = new RequestError(-999, message);
                }
                callFail(error);
            },
            fail: callFail,
            complete: noop,
        }));
    };
};


function upload(options) {
    if (typeof options !== 'object') {
        let message = '请求传参应为 object 类型，但实际传了 ' + (typeof options) + ' 类型';
        throw new RequestError(constants.ERR_INVALID_PARAMS, message);
    }

    let requireLogin = options.login;
    let success = options.success || noop;
    let fail = options.fail || noop;
    let complete = options.complete || noop;
    let originHeader = options.header || {};

    // 成功回调
    let callSuccess = function () {
        success.apply(null, arguments);
        complete.apply(null, arguments);
    };

    // 失败回调
    let callFail = function (error) {
        fail.call(null, error);
        complete.call(null, error);
    };

    // 是否已经进行过重试
    let hasRetried = false;

    if (requireLogin) {
        doRequestWithLogins();
    } else {
        doRequests();
    }

    // 登录后再请求
    function doRequestWithLogins() {
        loginLib.login({
            success: doRequest,
            fail: callFail
        });
    }

    // 实际进行请求的方法
    function doRequests() {
        let authHeader = buildSessionHeader();

        wx.uploadFile(utils.extend({}, options, {
            header: utils.extend({}, originHeader, authHeader),
            success: function (response) {
                let data = response.data;

                // 如果响应的数据里面包含 SDK Magic ID，表示被服务端 SDK 处理过，此时一定包含登录态失败的信息
                if (data && data[constants.WX_SESSION_TOKEN]) {
                    // 清除登录态
                    Session.clear();

                    let error, message;
                    if (data.error === constants.ERR_INVALID_SESSION) {
                        // 如果是登录态无效，并且还没重试过，会尝试登录后刷新凭据重新请求
                        if (!hasRetried) {
                            hasRetried = true;
                            doRequestWithLogin();
                            return;
                        }

                        message = '登录态已过期';
                        error = new RequestError(data.error, message);
                    } else {
                        message = '鉴权服务器检查登录态发生错误(' + (data.error || 'OTHER') + '): ' + (data.message || '未知错误');
                        error = new RequestError(constants.ERR_CHECK_LOGIN_FAILED, message);
                    }
                    callFail(error);
                    return;
                }
                callSuccess.apply(null, arguments);
            },

            fail: callFail,
            complete: noop,
        }));
    };

};

module.exports = {
    RequestError: RequestError,
    request: request,
    upload: upload,
    buildSessionHeader: buildSessionHeader
};
